﻿using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

namespace UFrame.UI
{
    [RequireComponent(typeof(GridLayoutGroup))]
    public class InfinityGridLayoutGroup : MonoBehaviour
    {
        /// <summary>
        /// 实现无限滚动，需要的最少的child数量。屏幕上能看到的+一行看不到的，
        /// 比如我在屏幕上能看到 2 行，每一行 2 个。则这个值为 2行*2个 + 1 行* 2个 = 6个。
        /// </summary>
        [Header("屏幕上能看到 2 行，每一行 2 个。则这个值为 2行*2个 + 1 行* 2个 = 6个")]
        public int minAmount = 0;
        private int amount = 0;
        
        private RectTransform rectTransform;
        private GridLayoutGroup layoutGroup;
        private ContentSizeFitter contentSizeFitter;
        private ScrollRect scrollRect;
        private List<RectTransform> children = new List<RectTransform>();
        private Vector2 startPosition;
        public Action<int, Transform> onUpdateBack = null;

        private int realIndex = -1;
        private int realIndexUp = -1; //从下往上;

        private bool hasInit = false;
        private Vector2 gridLayoutSize;
        private Vector2 gridLayoutPos;
        private Dictionary<Transform, Vector2> childsAnchoredPos = new Dictionary<Transform, Vector2>();
        private Dictionary<Transform, int> childsSiblingIndex = new Dictionary<Transform, int>();

        public int offsetHeight = 300;

        public void Awake()
        {
            layoutGroup = GetComponent<GridLayoutGroup>();
            contentSizeFitter = GetComponent<ContentSizeFitter>();
        }

        public void Init(int count)
        {
            amount = count;
            if (gameObject.activeInHierarchy)
            {
                StartCoroutine(InitChildren());
            }
        }


        private void CreateChild()
        {
            //创建子节点
            if (transform.childCount < amount)
            {
                int createCount = amount - transform.childCount;
                for (int i = 0; i < createCount; i++)
                {
                    var goRow = GameObject.Instantiate(transform.GetChild(0).gameObject);
                    goRow.transform.SetParent(transform);
                }
            }
        }

        private IEnumerator InitChildren()
        {
            yield return 0;
            
            CreateChild();
            yield return null;
            layoutGroup.enabled = true;
            contentSizeFitter.enabled = true;
            yield return new WaitForFixedUpdate();
            
            layoutGroup.enabled = false;
            contentSizeFitter.enabled = false;
            
            if (!hasInit)
            {
                //获取Grid的宽度;
                rectTransform = GetComponent<RectTransform>();
                gridLayoutPos = rectTransform.anchoredPosition;
                gridLayoutSize = rectTransform.sizeDelta;

                //注册ScrollRect滚动回调;
                scrollRect = transform.parent.GetComponentInParent<ScrollRect>();
                scrollRect.onValueChanged.AddListener((data) => { ScrollCallback(data); });

                //获取所有child anchoredPosition 以及 SiblingIndex;
                for (int index = 0; index < transform.childCount; index++)
                {
                    Transform child = transform.GetChild(index);
                    RectTransform childRectTrans = child.GetComponent<RectTransform>();
                    childsAnchoredPos.Add(child, childRectTrans.anchoredPosition);
                    childsSiblingIndex.Add(child, child.GetSiblingIndex());
                }
            }
            else
            {
                rectTransform.anchoredPosition = gridLayoutPos;
                rectTransform.sizeDelta = gridLayoutSize;
                children.Clear();
                realIndex = -1;
                realIndexUp = -1;

                //children重新设置上下顺序;
                foreach (var info in childsSiblingIndex)
                {
                    info.Key.SetSiblingIndex(info.Value);
                }

                //children重新设置anchoredPosition;
                for (int index = 0; index < transform.childCount; index++)
                {
                    Transform child = transform.GetChild(index);
                    RectTransform childRectTrans = child.GetComponent<RectTransform>();
                    if (childsAnchoredPos.ContainsKey(child))
                    {
                        childRectTrans.anchoredPosition = childsAnchoredPos[child];
                    }
                    else
                    {
                        Debug.LogError("childsAnchoredPosition no contain " + child.name);
                    }
                }

                //layoutGroup.SetLayoutVertical();
                //layoutGroup.CalculateLayoutInputVertical();
            }

            //获取所有child;
            for (int index = 0; index < transform.childCount; index++)
            {
                Transform trans = transform.GetChild(index);
                trans.gameObject.SetActive(true);
                children.Add(trans.GetComponent<RectTransform>());
                UpdateChildrenCallback(children.Count - 1, trans); //初始化前面几个;
            }

            startPosition = rectTransform.anchoredPosition;
            realIndex = children.Count - 1;
            //Debug.Log( scrollRect.transform.TransformPoint(Vector3.zero));
            // Debug.Log(transform.TransformPoint(children[0].localPosition));

            hasInit = true;
            int col = 3;
            if (this.layoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
            {
                col = this.layoutGroup.constraintCount;
            }

            int rowIndex = (amount / col + amount % col);
            rectTransform.sizeDelta =
                new Vector2(0, (layoutGroup.cellSize.y + layoutGroup.spacing.y) * rowIndex);
        }


        private void ScrollCallback(Vector2 data)
        {
            UpdateChildren();
        }

        private void UpdateChildren()
        {
            if (transform.childCount < minAmount)
            {
                return;
            }

            Vector2 currentPos = rectTransform.anchoredPosition;
            if (layoutGroup.constraint == GridLayoutGroup.Constraint.FixedColumnCount)
            {
                UpdateUpToDown(currentPos);
            }
            else
            {
                UpdateLeftToRight(currentPos);
            }

            startPosition = currentPos;
        }

        private void UpdateChildrenCallback(int index, Transform trans)
        {
            onUpdateBack?.Invoke(index, trans);
        }


        public void UpdateUpToDown(Vector2 currentPos)
        {
            float offsetY = currentPos.y - startPosition.y;

            if (offsetY > 0)
            {
                //向上拉，向下扩展;

                if (realIndex >= amount - 1)
                {
                    startPosition = currentPos;
                    return;
                }

                var rtTran = scrollRect.GetComponent<RectTransform>();
                var height2 = rtTran.rect.height / 2;
                Vector3 top = new Vector3(0, height2, 0); //先找到画布的顶部点 = 高度 / 2
                float scrollRectUp = scrollRect.transform.TransformPoint(top).y;

                var firstCell = children[0];
                var y = firstCell.anchoredPosition.y -
                        layoutGroup.cellSize.y * (firstCell.anchorMin.y + firstCell.anchorMax.y);

                Vector3 childBottomLeft = new Vector3(firstCell.anchoredPosition.x, y, 0f);

                float childBottom = transform.TransformPoint(childBottomLeft).y;
                //Debug.Log("单元格Y: " + y + "  当前画布Y：" + scrollRectUp + " childBottom:" + childBottom + "  height2:" + height2);
                if (childBottom >= scrollRectUp)
                {
                    //Debug.Log("childBottom >= scrollRectUp");

                    //移动到底部;
                    int z = 0;
                    for (int index = 0; index < layoutGroup.constraintCount; index++)
                    {
                        var rectTf = children[index];
                        rectTf.SetAsLastSibling();

                        rectTf.anchoredPosition = new Vector2(rectTf.anchoredPosition.x,
                            children[children.Count - 1].anchoredPosition.y - layoutGroup.cellSize.y -
                            layoutGroup.spacing.y);

                        realIndex++;

                        if (realIndex > amount - 1)
                        {
                            rectTf.gameObject.SetActive(false);
                        }
                        else
                        {
                            UpdateChildrenCallback(realIndex, rectTf);
                        }

                        z++;
                    }

                    if (z != layoutGroup.constraintCount)
                    {
                        Debug.LogError("没有移动3个" + z);
                    }

                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向下拉，下面收缩;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }

                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorBottom =
                    new Vector3(0, -scrollRectTransform.rect.height - layoutGroup.spacing.y, 0f);
                float scrollRectBottom = scrollRect.transform.TransformPoint(scrollRectAnchorBottom).y;
                var lastChild = children[children.Count - 1];
                Vector3 childUpLeft = new Vector3(lastChild.anchoredPosition.x,
                    lastChild.anchoredPosition.y, 0f);

                float childUp = transform.TransformPoint(childUpLeft).y;

                if (childUp < scrollRectBottom)
                {
                    //Debug.Log("childUp < scrollRectBottom");

                    //把底部的一行 移动到顶部
                    for (int index = 0; index < layoutGroup.constraintCount; index++)
                    {
                        int c = children.Count - 1;
                        int cIndex = c - index;
                        var cChild = children[cIndex];
                        cChild.SetAsFirstSibling();

                        cChild.anchoredPosition = new Vector2(
                            cChild.anchoredPosition.x,
                            children[0].anchoredPosition.y + layoutGroup.cellSize.y + layoutGroup.spacing.y);

                        cChild.gameObject.SetActive(true);

                        UpdateChildrenCallback(realIndex - children.Count - index, cChild);
                    }

                    realIndex -= layoutGroup.constraintCount;

                    //GridLayoutGroup 底部缩短;
                    //rectTransform.sizeDelta -= new Vector2(0, layoutGroup.cellSize.y + layoutGroup.spacing.y);

                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }
                }
            }
        }

        public void UpdateLeftToRight(Vector2 currentPos)
        {
            float offsetX = currentPos.x - startPosition.x;

            if (offsetX < 0)
            {
                //向左拉，向右扩展;
                {
                    if (realIndex >= amount - 1)
                    {
                        startPosition = currentPos;
                        return;
                    }

                    float scrollRectLeft = scrollRect.transform.TransformPoint(Vector3.zero).x;

                    Vector3 childBottomRight = new Vector3(children[0].anchoredPosition.x + layoutGroup.cellSize.x,
                        children[0].anchoredPosition.y, 0f);
                    float childRight = transform.TransformPoint(childBottomRight).x;

                    // Debug.LogError("childRight=" + childRight);

                    if (childRight <= scrollRectLeft)
                    {
                        //Debug.Log("childRight <= scrollRectLeft");

                        //移动到右边;
                        for (int index = 0; index < layoutGroup.constraintCount; index++)
                        {
                            var cChild = children[index];
                            cChild.SetAsLastSibling();

                            cChild.anchoredPosition = new Vector2(
                                children[children.Count - 1].anchoredPosition.x + layoutGroup.cellSize.x +
                                layoutGroup.spacing.x, cChild.anchoredPosition.y);

                            realIndex++;

                            if (realIndex > amount - 1)
                            {
                                cChild.gameObject.SetActive(false);
                            }
                            else
                            {
                                UpdateChildrenCallback(realIndex, cChild);
                            }
                        }

                        //GridLayoutGroup 右侧加长;
                        rectTransform.sizeDelta +=
                            new Vector2(layoutGroup.cellSize.x + layoutGroup.spacing.x, 0);

                        //更新child;
                        for (int index = 0; index < children.Count; index++)
                        {
                            children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                        }
                    }
                }
            }
            else
            {
                //Debug.Log("Drag Down");
                //向右拉，右边收缩;
                if (realIndex + 1 <= children.Count)
                {
                    startPosition = currentPos;
                    return;
                }

                RectTransform scrollRectTransform = scrollRect.GetComponent<RectTransform>();
                Vector3 scrollRectAnchorRight =
                    new Vector3(scrollRectTransform.rect.width + layoutGroup.spacing.x, 0, 0f);
                float scrollRectRight = scrollRect.transform.TransformPoint(scrollRectAnchorRight).x;

                var lastChild = children[children.Count - 1];
                Vector3 childUpLeft = new Vector3(lastChild.anchoredPosition.x,
                    lastChild.anchoredPosition.y, 0f);

                float childLeft = transform.TransformPoint(childUpLeft).x;

                if (childLeft >= scrollRectRight)
                {
                    //Debug.LogError("childLeft > scrollRectRight");

                    //把右边的一行 移动到左边;
                    for (int index = 0; index < layoutGroup.constraintCount; index++)
                    {
                        int c = children.Count - 1;
                        int cIndex = c - index;

                        var cChild = children[cIndex];
                        cChild.SetAsFirstSibling();

                        cChild.anchoredPosition = new Vector2(
                            children[0].anchoredPosition.x - layoutGroup.cellSize.x - layoutGroup.spacing.x,
                            cChild.anchoredPosition.y);

                        cChild.gameObject.SetActive(true);

                        UpdateChildrenCallback(realIndex - children.Count - index, cChild);
                    }


                    //GridLayoutGroup 右侧缩短;
                    rectTransform.sizeDelta -= new Vector2(layoutGroup.cellSize.x + layoutGroup.spacing.x, 0);

                    //更新child;
                    for (int index = 0; index < children.Count; index++)
                    {
                        children[index] = transform.GetChild(index).GetComponent<RectTransform>();
                    }

                    realIndex -= layoutGroup.constraintCount;
                }
            }
        }
    }
}